/**
 *  手撕单例模式
 * 
 *  1.单例模式，顾名思义只有一个实例，因此要防止用户构造、拷贝、赋值
 *      构造函数、拷贝构造、赋值重载都要私有化，必要时也可以让析构函数也私有化
 *
 *  2.需要一个静态方法获取单例实例
 *
 *  3.懒汉式单例需要注意线程安全：如果多个线程同时调用 get_instance
 *    创建实例，可能造成创建出多个实例
 *          传统的做法：用互斥锁。并用double check提高效率。
 *          C++11之后：使用static局部变量。
 */

#include <iostream>
#include <mutex>

/* 懒汉式单例模式(传统的做法) */
class Singleton_1
{
private:
    static Singleton_1* instance;
    static std::mutex mutex_;

public:
    static Singleton_1* getInstance()
    {
        std::lock_guard<std::mutex> lock(mutex_);
        if (instance == nullptr) {
            // 仅当实例不存在时创建实例
            instance = new Singleton_1();
        }
        return instance;
    }

    static Singleton_1* getInstance_double_check()
    {
        // 如果没有double check，则每次getInstance()都需要加锁，效率低下

        // 第一次检查（不加锁）
        if (instance == nullptr) {
            std::lock_guard<std::mutex> lock(mutex_);
            // 第二次检查（加锁后）
            if (instance == nullptr) {
                // 仅当实例不存在时创建实例
                instance = new Singleton_1();
            }
        }
        return instance;
    }

    Singleton_1(const Singleton_1&) = delete;
    Singleton_1& operator=(const Singleton_1&) = delete;

private:
    Singleton_1() {}
    ~Singleton_1() {}
};

// 一定要类外定义(初始化)静态成员变量
Singleton_1* Singleton_1::instance = nullptr;
std::mutex Singleton_1::mutex_;

/* 懒汉式单例模式(静态局部变量) */
class Singleton
{
public:
    // 提供静态方法获取实例
    static Singleton& get_instance()
    {
        // C++11之后，静态局部变量的初始化已经是线程安全
        static Singleton ins;
        return ins;
    }

    void do_something()
    {
        std::cout << "Do something.\n";
    }

private:
    // 构造函数私有化
    Singleton() {}

    // 析构函数私有化：用户无法通过对象指针 delete 当前类的实例
    ~Singleton() {}

    // 删除拷贝、赋值
    Singleton(const Singleton& other) = delete;
    Singleton& operator=(const Singleton& other) = delete;
};

/* 饿汉式单例模式 */
class Singleton_Hunger
{
    static Singleton_Hunger*
            instance; // 注：静态成员变量类内声明，类外定义(初始化)

public:
    static Singleton_Hunger* getInstance()
    {
        return instance; // 天然是线程安全的
    }

    Singleton_Hunger(const Singleton_Hunger&) = delete;
    Singleton_Hunger& operator=(const Singleton_Hunger&) = delete;

private:
    Singleton_Hunger() {}
    ~Singleton_Hunger() {}
};

// 饿汉式单例：需要在类外初始化静态成员
Singleton_Hunger* Singleton_Hunger::instance = new Singleton_Hunger();

int main()
{
    // Singleton s = Singleton::get_instance(); // Compile error
    // Singleton* sin = &Singleton::get_instance();
    // delete sin; // Compile error

    return 0;
}